home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume10 / comobj.lisp / part10 < prev    next >
Encoding:
Text File  |  1987-08-02  |  36.0 KB  |  888 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i084:  Common Objects, Common Loops, Common Lisp, Part10/13
  5. Message-ID: <755@uunet.UU.NET>
  6. Date: 3 Aug 87 21:17:56 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 877
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: Roy D'Souza <dsouza%hplabsc@hplabs.HP.COM>
  12. Posting-number: Volume 10, Issue 84
  13. Archive-name: comobj.lisp/Part10
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 10 (of 13)."
  22. # Contents:  braid.l
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'braid.l' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'braid.l'\"
  26. else
  27. echo shar: Extracting \"'braid.l'\" \(34250 characters\)
  28. sed "s/^X//" >'braid.l' <<'END_OF_FILE'
  29. X;;;-*-Mode:LISP; Package:(PCL (LISP WALKER)); Base:10; Syntax:Common-lisp -*-
  30. X;;;
  31. X;;; *************************************************************************
  32. X;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
  33. X;;;
  34. X;;; Use and copying of this software and preparation of derivative works
  35. X;;; based upon this software are permitted.  Any distribution of this
  36. X;;; software or derivative works must comply with all applicable United
  37. X;;; States export control laws.
  38. X;;; 
  39. X;;; This software is made available AS IS, and Xerox Corporation makes no
  40. X;;; warranty about the software, its performance or its conformity to any
  41. X;;; specification.
  42. X;;; 
  43. X;;; Any person obtaining a copy of this software is requested to send their
  44. X;;; name and post office or electronic mail address to:
  45. X;;;   CommonLoops Coordinator
  46. X;;;   Xerox Artifical Intelligence Systems
  47. X;;;   2400 Hanover St.
  48. X;;;   Palo Alto, CA 94303
  49. X;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
  50. X;;;
  51. X;;; Suggestions, comments and requests for improvements are also welcome.
  52. X;;; *************************************************************************
  53. X;;;
  54. X;;; The meta-braid and defstruct.
  55. X;;;
  56. X;;; NOTE: This file must be loaded before it can be compiled.
  57. X
  58. X#| *** TO DO ***
  59. X
  60. X|#
  61. X(in-package 'pcl)
  62. X
  63. X  ;;   
  64. X;;;;;; Medium-level support for the class CLASS.
  65. X  ;;   
  66. X;;; The low-level macros are defined by the file portable-low (or a special
  67. X;;; version) of that file if there is one for this implementation.  This is
  68. X;;; the lowest-level completely portable code which operates on instances
  69. X;;; with meta-class class.
  70. X
  71. X(defmacro get-static-slot--class (iwmc-class slot-index)
  72. X  `(%static-slot-storage-get-slot--class
  73. X     (iwmc-class-static-slots ,iwmc-class)
  74. X     ,slot-index))
  75. X
  76. X(defmacro get-dynamic-slot--class (iwmc-class slot-name default)
  77. X  `(%dynamic-slot-storage-get-slot--class
  78. X     (iwmc-class-dynamic-slots ,iwmc-class)
  79. X     ,slot-name
  80. X     ,default))
  81. X
  82. X(defmacro remove-dynamic-slot--class (iwmc-class slot-name)
  83. X  `(%dynamic-slot-storage-remove-slot--class
  84. X     (iwmc-class-dynamic-slots ,iwmc-class)
  85. X     ,slot-name))
  86. X
  87. X
  88. X  ;;
  89. X;;;;;; defmeth  -- defining methods
  90. X  ;;
  91. X;;; We need to be able to define something like methods before we really have
  92. X;;; real method functionality available.
  93. X;;;
  94. X;;; defmeth expands by calling expand-defmeth, this means that we can define
  95. X;;; an early version of defmeth just by defining an early version of expand-
  96. X;;; defmeth.
  97. X;;;
  98. X(defmacro defmethod (&rest args)
  99. X ;(declare (zl:arglist name qualifier* arglist &body body))
  100. X  (let ((name (pop args))
  101. X    (qualifiers ())
  102. X    (arglist ())
  103. X    (body nil))
  104. X    (multiple-value-setq (qualifiers args) (defmethod-qualifiers args))
  105. X    (setq arglist (pop args)
  106. X      body args)
  107. X    `(defmeth (,name . ,qualifiers) ,arglist . ,body)))
  108. X
  109. X(defmacro defmethod-setf (&rest args)
  110. X  (let ((name (pop args))
  111. X    (qualifiers ())
  112. X    (arglist ())
  113. X    (new-value-arglist ())
  114. X    (body nil))
  115. X    (multiple-value-setq (qualifiers args) (defmethod-qualifiers args))
  116. X    (setq arglist (pop args)
  117. X      new-value-arglist (pop args)
  118. X      body args)
  119. X    `(defmeth (,name (:setf ,new-value-arglist) ,.qualifiers) ,arglist
  120. X       ,@body)))
  121. X
  122. X(defun defmethod-qualifiers (args)
  123. X  (declare (values qualifiers arglist-and-body))
  124. X  (let ((qualifiers ()))
  125. X    (loop (if (and (car args) (listp (car args)))
  126. X          (return (values (nreverse qualifiers) args))
  127. X          (push (pop args) qualifiers)))))
  128. X
  129. X(defun defmethod-argument-specializers (arglist)
  130. X  (let ((arg (car arglist)))
  131. X    (cond ((null arglist) nil)
  132. X      ((memq arg '(&optional &rest &key &aux)) nil) ;Don't allow any
  133. X                                                        ;argument specializers
  134. X                                                    ;after one of these.
  135. X      ((memq arg lambda-list-keywords)            ;Or one of these!!
  136. X       (warn "Unrecognized lambda-list keyword ~S in arglist.~%~
  137. X                  Assuming that no argument specializers appear after it."
  138. X         arg)
  139. X       nil)
  140. X      (t
  141. X       (let ((tail (defmethod-argument-specializers (cdr arglist)))
  142. X         (specializer (and (listp arg) (cadr arg))))
  143. X         (or (and tail (cons (or specializer 't) tail))
  144. X         (and specializer (cons specializer ()))))))))
  145. X
  146. X
  147. X(defmacro defmeth (name&options arglist &body body)
  148. X  (expand-defmeth name&options arglist body))
  149. X
  150. X(eval-when (compile load eval)
  151. X  ;; Make sure we call bootstrap-expand-defmeth during bootstrapping.
  152. X  ;;  - Can't say (setf (symbol-fu ..) #'bootstrap-expand-defmeth because
  153. X  ;;    bootstrap-expand-defmeth isn't defined yet and that isn't legal
  154. X  ;;    in Common Lisp.
  155. X  ;;  - Can't say (setf (symbol-fu ..) 'bootstrap-expand-defmeth because
  156. X  ;;    not all Common Lisps like having symbols in the function cell.
  157. X  (setf (symbol-function 'expand-defmeth)
  158. X    #'(lambda (name&options arglist body)
  159. X        (bootstrap-expand-defmeth name&options arglist body)))
  160. X  )
  161. X
  162. X  ;;   
  163. X;;;;;; Early methods
  164. X  ;;   
  165. X
  166. X(defvar *real-methods-exist-p*)
  167. X(eval-when (compile load eval)
  168. X  (setq *real-methods-exist-p* nil))
  169. X
  170. X(eval-when (load)  
  171. X  (setq *error-when-defining-method-on-existing-function* 'bootstrapping))
  172. X
  173. X(defvar *protected-early-selectors* '(print-instance))
  174. X
  175. X(defparameter *early-defmeths* ())
  176. X
  177. X(defmacro simple-type-specs (arglist)
  178. X  `(let ((type-specs
  179. X       (iterate ((arg in ,arglist))
  180. X            (until (memq arg '(&optional &rest &key &aux)))
  181. X            (collect (if (listp arg) (cadr arg) 't)))))
  182. X     (setq type-specs (nreverse type-specs))
  183. X     (iterate ((type-spec in type-specs))
  184. X          (until (neq type-spec 't))
  185. X          (pop type-specs))
  186. X     (nreverse type-specs)))
  187. X
  188. X(defmacro simple-without-type-specs (arglist)
  189. X  `(iterate ((loc on ,arglist))
  190. X        (cond ((memq (car loc) '(&optional &rest &key &aux))
  191. X           (join loc) (until t))
  192. X          (t
  193. X           (collect (if (listp (car loc))
  194. X                (caar loc)
  195. X                (car loc)))))))
  196. X(defmacro simple-args (arglist)
  197. X  `(iterate ((arg in ,arglist))
  198. X        (until (eq arg '&aux))
  199. X        (unless (memq arg '(&optional &rest &key))
  200. X          (collect (if (listp arg) (car arg) arg)))))
  201. X
  202. X(defun bootstrap-expand-defmeth (name&options arglist body)
  203. X  ;; Some SIMPLE local macros for getting the type-specifiers out of the
  204. X  ;; argument list.  Unfortunately, it is important that these simple
  205. X  ;; macros and the methods which come along later and do this job better
  206. X  ;; be compatible.  This will become less of an issue once methods don't
  207. X  ;; have names anymore.
  208. X; (macrolet ()             
  209. X    (multiple-value-bind (documentation declares body)
  210. X        (extract-declarations body)
  211. X      (or (listp name&options) (setq name&options (list name&options)))
  212. X      (keyword-parse ((setf () setfp))
  213. X                     (cdr name&options)
  214. X        (let* ((name (car name&options))
  215. X               (discriminator-name (if setfp
  216. X                       (make-setf-discriminator-name name)
  217. X                       name))
  218. X               (method-name (if setfp
  219. X                                (make-setf-method-name
  220. X                  name
  221. X                  (simple-type-specs setf)
  222. X                  (simple-type-specs arglist))
  223. X                                (make-method-name
  224. X                  name (simple-type-specs arglist))))
  225. X               (method-arglist (simple-without-type-specs
  226. X                                 (if setfp
  227. X                                     (cons (car arglist)
  228. X                       (append setf (cdr arglist)))
  229. X                                     arglist))))
  230. X          `(progn
  231. X             ;; Record this early defmeth so that fixup-early-defmeths will
  232. X             ;; know to fix it up later.
  233. X             (eval-when (compile load eval)
  234. X               (record-early-defmeth
  235. X         ',discriminator-name ',name&options ',arglist ',body))
  236. X         (record-definition ',discriminator-name 'method)
  237. X             (defun ,method-name ,method-arglist
  238. X               ,@(and documentation (list documentation))
  239. X               ,@declares
  240. X;              #+Symbolics(declare (sys:function-parent ,name defmeth))
  241. X               . ,body)         
  242. X         ,(unless (memq discriminator-name *protected-early-selectors*)
  243. X        `(eval-when (load eval)
  244. X           (setf (symbol-function ',discriminator-name)
  245. X             (symbol-function ',method-name))))
  246. X             ,@(and setfp
  247. X            (not (memq discriminator-name *protected-early-selectors*))
  248. X                    (let ((args (simple-without-type-specs arglist))
  249. X                          (setf-args (simple-without-type-specs setf)))
  250. X                      `((defsetf ,name ,args ,setf-args
  251. X                          (list ',discriminator-name
  252. X                                ,(car args)
  253. X                                ,@(simple-args setf)
  254. X                                ,@(simple-args (cdr args))))))))))))
  255. X;)
  256. X
  257. X(defun record-early-defmeth (discriminator-name name&options arglist body)
  258. X  (pushnew (list* 'defmeth discriminator-name name&options arglist body)
  259. X       *early-defmeths*
  260. X       :test #'equal))
  261. X
  262. X(defun record-early-discriminator (discriminator-name)
  263. X  (pushnew (list 'clear discriminator-name) *early-defmeths* :test #'equal))
  264. X
  265. X(defun record-early-method-fixup (form)
  266. X  (pushnew (list 'eval form) *early-defmeths* :test #'equal))
  267. X
  268. X(defmacro fix-early-defmeths ()
  269. X  (let ((resets ())
  270. X    (evals ()))
  271. X    (dolist (entry *early-defmeths*)
  272. X      (ecase (car entry)
  273. X    (defmeth (push (cons 'defmeth (cddr entry)) evals)
  274. X         (push (cadr entry) resets))
  275. X    (clear   (push (cadr entry) resets))
  276. X    (eval    (push (cadr entry) evals))))    
  277. X    `(progn
  278. X       ;; The first thing to do is go through and get rid of all the old
  279. X       ;; discriminators.  This only needs to happen when we are being
  280. X       ;; loaded into the same VMem we were compiled in.  The WHEN is
  281. X       ;; making that optimization.
  282. X       (defun fix-early-defmeths-1 ()     
  283. X     (when (discriminator-named ',(car resets))       
  284. X       (dolist (x ',resets) (setf (discriminator-named x) nil))))
  285. X       (fix-early-defmeths-1)
  286. X       ,@evals)))
  287. X
  288. X#| This is useful for debugging.
  289. X(defmacro unfix-early-defmeths ()
  290. X  `(progn
  291. X     (do-symbols (x)
  292. X       (remprop x 'discriminator)
  293. X       (remprop x 'setf-discriminator))
  294. X     . ,(mapcar '(lambda (x) (cons 'defmeth x)) (reverse *early-defmeths*))))
  295. X
  296. X(unfix-early-defmeths)
  297. X|#
  298. X
  299. X(defun make-setf-discriminator-name (name)
  300. X  (intern (string-append name " :SETF-discriminator")
  301. X      (symbol-package name)))
  302. X
  303. X(defun make-method-name (selector type-specifiers)
  304. X  (intern (apply #'string-append
  305. X                      (list* "Method "
  306. X                             selector
  307. X                             " "
  308. X                             (make-method-name-internal type-specifiers)))
  309. X      (symbol-package selector)))
  310. X
  311. X(defun make-setf-method-name (selector setf-type-specifiers type-specifiers)
  312. X  (intern (apply #'string-append
  313. X                      (list* "Method "
  314. X                             selector
  315. X                             " ("
  316. X                             (apply #'string-append
  317. X                                    ":SETF "
  318. X                                    (make-method-name-internal setf-type-specifiers))
  319. X                             ") "
  320. X                             (make-method-name-internal type-specifiers)))
  321. X      (symbol-package selector)))
  322. X
  323. X(defun make-method-name-internal (type-specifiers)
  324. X  (if type-specifiers
  325. X      (iterate ((type-spec on type-specifiers))
  326. X        (collect (string (car type-spec)))
  327. X        (when (cdr type-spec) (collect " ")))
  328. X      '("Default")))
  329. X  
  330. X
  331. X
  332. X  ;;
  333. X;;;;;; SLOTDS and DS-OPTIONS
  334. X  ;;
  335. X;;;
  336. X;;; A slot-description is the thing which appears in a defstruct.  A SLOTD is
  337. X;;; an internal description of a slot.
  338. X;;;
  339. X;;; The SLOTD structure corresponds to the kind of slot the structure-class
  340. X;;; meta-class creates (the kind of slot that appears in Steele Edition 1).
  341. X;;; Other metaclasses which need to have more elaborate slot options and
  342. X;;; slotds, they :include that class in their slotds.
  343. X;;;
  344. X;;; slotds are :type list for 2 important reasons:
  345. X;;;   - so that looking up a slotd in a list of lists will compile
  346. X;;;     into a call to assq
  347. X;;;   - PCL assumes only the existence of the simplest of defstructs
  348. X;;;     this allows PCL to be used to implement a real defstruct.
  349. X;;;     
  350. X(defstruct (essential-slotd (:type list)
  351. X                (:constructor make-slotd--essential-class))
  352. X  name)
  353. X
  354. X;;;
  355. X;;; Slotd-position is used to find the position of a slot with a particular
  356. X;;; name in a list of slotds.  Specifically it is used in the case of a
  357. X;;; get-slot cache miss to find this slot index.  That means it is used in
  358. X;;; about 2% of the total slot accesses so it should be fast.
  359. X;;; 
  360. X(defmacro slotd-position (slotd-name slotds)
  361. X  `(let ((slotd-name ,slotd-name))
  362. X     (do ((pos 0 (+ pos 1))
  363. X      (slotds ,slotds (cdr slotds)))
  364. X     ((null slotds) nil)
  365. X       (declare (type integer pos) (type list slotds))
  366. X       (and (eq slotd-name (slotd-name (car slotds)))
  367. X        (return pos)))))
  368. X
  369. X(defmacro slotd-member (slotd-name slotds)                  ;I wonder how
  370. X  `(member ,slotd-name ,slotds :test #'eq :key #'slotd-name)) ;many compilers
  371. X                                      ;are really
  372. X                                      ;smart enough.
  373. X(defmacro slotd-assoc (slotd-name slotds)    
  374. X  `(assq ,slotd-name ,slotds))
  375. X
  376. X;;;
  377. X;;; Once defstruct-options are defaulted and parsed, they are stored in a
  378. X;;; ds-options (defstruct-options) structure.  This modularity makes it
  379. X;;; easier to build the meta-braid which has to do some slot and option
  380. X;;; parsing long before the real new defstruct exists.  More importantly,
  381. X;;; this allows new meta-classes to inherit the option parsing code 
  382. X;;; from other metaclasses.
  383. X;;;
  384. X(defstruct (ds-options (:constructor make-ds-options--class))
  385. X  name
  386. X  constructors             ;The constructor argument, a list whose car is the
  387. X               ;name of the constructor and whose cadr if present
  388. X                           ;is the argument-list for the constructor.
  389. X  copier                   ;(defaulted) value of the :copier option.
  390. X  predicate                ;ditto for :predicate
  391. X  print-function           ;ditto for :print-function
  392. X  generate-accessors       ;ditto for :generate-accessors
  393. X  conc-name                ;ditto for :conc-name 
  394. X  includes                 ;The included structures (car of :include)
  395. X  slot-includes            ;The included slot modifications (cdr of :include)
  396. X  initial-offset           ;(defaulted) value of the :initial-offset option.
  397. X  )
  398. X
  399. X  
  400. X
  401. X  ;;
  402. X;;;;;; The beginnings of the meta-class CLASS (parsing the defstruct)
  403. X  ;;   
  404. X
  405. X(defmeth make-ds-options ((class basic-class) name)
  406. X  (ignore class)
  407. X  (make-ds-options--class :name name))
  408. X
  409. X(defmeth parse-defstruct-options ((class basic-class) name options)
  410. X  (parse-defstruct-options-internal
  411. X    class name options
  412. X    (default-ds-options class name (make-ds-options class name))))
  413. X
  414. X(defmeth default-ds-options ((class basic-class) name ds-options)
  415. X  (ignore class)
  416. X  (setf
  417. X    (ds-options-constructors ds-options)       `((,(symbol-append "MAKE-"
  418. X                                  name)))
  419. X    (ds-options-copier ds-options)             (symbol-append "COPY-" name)
  420. X    (ds-options-predicate ds-options)          (symbol-append name "-P")
  421. X    (ds-options-print-function ds-options)     nil
  422. X    (ds-options-generate-accessors ds-options) 'method
  423. X    (ds-options-conc-name ds-options)          (symbol-append name "-")
  424. X    (ds-options-includes ds-options)           ()
  425. X    (ds-options-slot-includes ds-options)      ()
  426. X    (ds-options-initial-offset ds-options)     0)
  427. X  ds-options)
  428. X
  429. X(defmeth parse-defstruct-options-internal ((class basic-class)
  430. X                        name options ds-options)
  431. X  (ignore class name)
  432. X  (keyword-parse ((conc-name (ds-options-conc-name ds-options))
  433. X                  (constructor () constructor-p :allowed :multiple
  434. X                        :return-cdr t)
  435. X                  (copier (ds-options-copier ds-options))
  436. X                  (predicate (ds-options-predicate ds-options))
  437. X                  (include () include-p :return-cdr t)
  438. X                  (print-function () print-function-p)
  439. X                  (initial-offset (ds-options-initial-offset ds-options))
  440. X                  (generate-accessors (ds-options-generate-accessors
  441. X                    ds-options)))
  442. X                 options
  443. X    (setf (ds-options-conc-name ds-options) conc-name)
  444. X    (when constructor-p
  445. X      (setf (ds-options-constructors ds-options) constructor))
  446. X    (setf (ds-options-copier ds-options) copier)
  447. X    (setf (ds-options-predicate ds-options) predicate)
  448. X    (when include-p
  449. X      (destructuring-bind (includes . slot-includes) include
  450. X    (setf (ds-options-includes ds-options) (if (listp includes)
  451. X                           includes
  452. X                           (list includes))
  453. X          (ds-options-slot-includes ds-options) slot-includes)))
  454. X    (when print-function-p
  455. X      (setf (ds-options-print-function ds-options)
  456. X        (cond ((null print-function) nil)
  457. X          ((symbolp print-function) print-function)
  458. X          ((and (listp print-function)
  459. X            (eq (car print-function) 'lambda)
  460. X            (listp (cadr print-function)))
  461. X           print-function)
  462. X          (t
  463. X           (error "The :PRINT-FUNCTION option, ~S~%~
  464. X                           is not either nil or a function suitable for the~
  465. X                           function special form."
  466. X               print-function)))))
  467. X    (setf (ds-options-initial-offset ds-options) initial-offset)
  468. X    (setf (ds-options-generate-accessors ds-options) generate-accessors)
  469. X    ds-options))
  470. X
  471. X;;;
  472. X;;;
  473. X
  474. X(defvar *slotd-unsupplied* (list nil))
  475. X
  476. X(defstruct (class-slotd (:include essential-slotd)
  477. X            (:type list)
  478. X            (:conc-name slotd-)
  479. X            (:constructor make-slotd--class)
  480. X            (:copier copy-slotd))
  481. X  keyword
  482. X  (default *slotd-unsupplied*)
  483. X  (type *slotd-unsupplied*)
  484. X  (read-only *slotd-unsupplied*)
  485. X  (accessor *slotd-unsupplied*)
  486. X  (allocation *slotd-unsupplied*)
  487. X  get-function   ;NIL if no :get(put)-function argument was supplied.
  488. X  put-function   ;Otherwise, a function of two (three)arguments, the
  489. X                 ;object, the name of the slot (and the new-value).
  490. X  )
  491. X
  492. X(defmeth make-slotd ((class basic-class) &rest keywords-and-options)
  493. X  (ignore class)
  494. X  (apply #'make-slotd--class keywords-and-options))
  495. X
  496. X(defmeth parse-slot-descriptions ((class basic-class) ds-options slot-descriptions)
  497. X  (iterate ((slot-description in slot-descriptions))
  498. X    (collect (parse-slot-description class ds-options slot-description))))
  499. X
  500. X(defmeth parse-slot-description ((class basic-class) ds-options slot-description)
  501. X  (parse-slot-description-internal
  502. X    class ds-options slot-description (make-slotd class)))
  503. X
  504. X(defmeth parse-slot-description-internal ((class basic-class) ds-options slot-description slotd)
  505. X  (ignore class)
  506. X  (let ((conc-name (ds-options-conc-name ds-options))
  507. X        (generate-accessors (ds-options-generate-accessors ds-options)))
  508. X    #+Lucid (declare (special conc-name generate-accessors))
  509. X    (destructuring-bind (name default . args)
  510. X                        slot-description
  511. X      (keyword-bind ((type nil)
  512. X                     (read-only nil)
  513. X                     (generate-accessor generate-accessors)
  514. X                     (allocation :instance)
  515. X                     (get-function nil)
  516. X                     (put-function nil)
  517. X
  518. X             (accessor nil accessor-p)
  519. X             (initform nil)        ;ignore
  520. X             )
  521. X                    args
  522. X        #+Lucid(declare (special type read-only generate-accessor allocation
  523. X                                 get-function put-function))
  524. X        (check-member allocation '(:class :instance :dynamic)
  525. X                      :test #'eq
  526. X                      :pretty-name "the :allocation option")
  527. X        (setf (slotd-name slotd)         name
  528. X              (slotd-keyword slotd)      (make-keyword name)
  529. X              (slotd-default slotd)      default
  530. X              (slotd-type slotd)         type
  531. X              (slotd-read-only slotd)    read-only
  532. X              (slotd-accessor slotd)     (if accessor-p
  533. X                         accessor
  534. X                         (and generate-accessor
  535. X                          (if conc-name
  536. X                             (symbol-append conc-name
  537. X                                    name)
  538. X                             name)))
  539. X              (slotd-allocation slotd)   allocation
  540. X              (slotd-get-function slotd) (and get-function
  541. X                                              (if (and (consp get-function)
  542. X                                                       (eq (car get-function) 'function))
  543. X                                                  get-function
  544. X                                                  (list 'function get-function)))
  545. X              (slotd-put-function slotd) (and put-function
  546. X                                              (if (and (consp put-function)
  547. X                                                       (eq (car put-function) 'function))
  548. X                                                  put-function
  549. X                                                  (list 'function put-function))))
  550. X        slotd))))
  551. X
  552. X;;;
  553. X;;; Take two lists of slotds and return t if they describe an set of slots of
  554. X;;; the same shape.  Otherwise return nil.  Sets of slots are have the same
  555. X;;; same shape if they have they both have the same :allocation :instance
  556. X;;; slots and if those slots appear in the same order.
  557. X;;; 
  558. X(defun same-shape-slots-p (old-slotds new-slotds)
  559. X  (do ()
  560. X      ((and (null old-slotds) (null new-slotds)) t)
  561. X    (let* ((old (pop old-slotds))
  562. X       (new (pop new-slotds))
  563. X       (old-allocation (and old (slotd-allocation old)))
  564. X       (new-allocation (and new (slotd-allocation new))))
  565. X      ;; For the old and new slotd check all the possible reasons
  566. X      ;; why they might not match.
  567. X      ;;   - One or the other is null means that a slot either
  568. X      ;;     disappeared or got added.
  569. X      ;;   - The names are different means that a slot moved
  570. X      ;;     disappared or go added.
  571. X      ;;   - If the allocations are different, and one of them
  572. X      ;;     is :instance then a slot either became or ceased
  573. X      ;;     to be :allocation :instance.
  574. X      (when (or (null old)
  575. X        (null new)
  576. X        (neq (slotd-name old) (slotd-name new))
  577. X        (and (neq old-allocation new-allocation)
  578. X             (or (eq old-allocation :instance)
  579. X             (eq new-allocation :instance))))
  580. X    (return nil)))))
  581. X
  582. X(defmeth slots-with-allocation ((class basic-class) slotds allocation)
  583. X  (ignore class)
  584. X  (iterate ((slotd in slotds))
  585. X    (when (eq (slotd-allocation slotd) allocation)
  586. X      (collect slotd))))
  587. X
  588. X(defmeth slots-with-allocation-not ((class basic-class) slotds allocation)
  589. X  (ignore class)
  590. X  (iterate ((slotd in slotds))
  591. X    (unless (eq (slotd-allocation slotd) allocation)
  592. X      (collect slotd))))
  593. X
  594. X  ;;   
  595. X;;;;;; GET-SLOT and PUT-SLOT
  596. X  ;;
  597. X;;; Its still too early to fully define get-slot and put-slot since they need
  598. X;;; the meta-braid to work.
  599. X;;;
  600. X;;; But its nice if as part of defining the meta-braid we can define and compile
  601. X;;; code which does get-slots and setfs of get-slots and in order to do this we
  602. X;;; need to have get-slot around.  Actually we could do with just the defsetf of
  603. X;;; get-slot but might as well put all 3 here.
  604. X;;;
  605. X;;; The code bootstrap meta-braid defines with get-slot in it is all done with
  606. X;;; defmeth, so these get-slots will all get recompiled once the optimizers
  607. X;;; exist don't worry.
  608. X(defun get-slot (object slot-name)
  609. X  (get-slot-using-class (class-of object) object slot-name))
  610. X
  611. X(defun put-slot (object slot-name new-value)
  612. X  (put-slot-using-class (class-of object) object slot-name new-value))
  613. X
  614. X(defun setf-of-get-slot (new-value object slot-name)
  615. X  (put-slot-using-class (class-of object) object slot-name new-value))
  616. X
  617. X(defsetf get-slot (object slot-name &rest extra-args) (new-value)
  618. X  `(setf-of-get-slot ,new-value ,object ,slot-name . ,extra-args))
  619. X
  620. X(defun get-slot-always (object slot-name &optional default)
  621. X  (get-slot-using-class (class-of object) object slot-name t default))
  622. X
  623. X(defun put-slot-always (object slot-name new-value)
  624. X  (put-slot-using-class (class-of object) object slot-name new-value t))
  625. X
  626. X(defsetf get-slot-always (object slot-name &optional default) (new-value)
  627. X  `(put-slot-always ,object ,slot-name ,new-value))
  628. X
  629. X(defun remove-dynamic-slot (object slot-name)
  630. X  (remove-dynamic-slot-using-class (class-of object) object slot-name))
  631. X
  632. X
  633. X
  634. X
  635. X  ;;   
  636. X;;;;;; Actually bootstrapping the meta-braid
  637. X  ;;
  638. X;;;
  639. X;;; *meta-braid* is the list from which the initial meta-classes are created.
  640. X;;; The elements look sort of like defstructs.  The car of each element is
  641. X;;; the name of the class;  the cadr is the defstruct options;  the caddr is
  642. X;;; the slot-descriptions.
  643. X;;;
  644. X(defvar *meta-braid*
  645. X        '((t
  646. X            ((:include ()))
  647. X            ())
  648. X          (object
  649. X            ((:include (t)))
  650. X            ())
  651. X          (essential-class
  652. X            ((:include (object))
  653. X             (:conc-name class-))
  654. X            ((name nil)                    ;A symbol, the name of the class.
  655. X             (class-precedence-list ())    ;The class's class-precedence-list
  656. X                       ;see compute-class-precedence-list
  657. X             (local-supers ())           ;This class's direct superclasses.
  658. X         (local-slots ())
  659. X             (direct-subclasses ())       ;All the classes which have this
  660. X                       ;class on their local-supers.
  661. X         (direct-methods ())
  662. X         ))
  663. X          (basic-class
  664. X            ((:include (essential-class))
  665. X         (:conc-name class-))
  666. X            ((no-of-instance-slots 0)      ;The # of slots with :allocation :instance
  667. X                                           ;in an instance of this class.
  668. X             (instance-slots ())           ;The slotds of those slots.
  669. X             (non-instance-slots ())       ;The declared slots with :allocation other
  670. X                                           ;than :instance.  instance-slots + non-
  671. X                                           ;instance-slots = all-slots.
  672. X             (wrapper nil)                 ;The class-wrapper which instances of
  673. X                                           ;this class point to.
  674. X         (direct-discriminators ())
  675. X         (discriminators-which-combine-methods ())
  676. X             (prototype nil :get-function (lambda (c slot-name)
  677. X                                            (ignore slot-name)
  678. X                                            (or (get-slot c 'prototype)
  679. X                                                (setf (get-slot c 'prototype)
  680. X                                                      (make c)))))      
  681. X             (ds-options ())))
  682. X      (class
  683. X        ((:include (basic-class)))
  684. X        ())))
  685. X
  686. X;;;
  687. X;;; *bootstrap-slots* is a list of the slotds corresponding to the slots of class
  688. X;;; class with :allocation :instance.  It is used by bootstrap-get-slot during the
  689. X;;; bootstrapping of the meta-braid.
  690. X;;;
  691. X(defvar *bootstrap-slots*)
  692. X
  693. X(defmacro bootstrap-get-slot (iwmc-class slot-name)
  694. X  `(get-static-slot--class ,iwmc-class
  695. X        (%convert-slotd-position-to-slot-index 
  696. X          (slotd-position ,slot-name *bootstrap-slots*))))
  697. X
  698. X(defun bootstrap-initialize (iwmc-class name includes local-slots
  699. X                                        prototype wrapper ds-options)
  700. X  (let ((cpl ())
  701. X        (all-slots ())
  702. X        (instance-slots ()))
  703. X    (setf (bootstrap-get-slot iwmc-class 'name) name)
  704. X    (setf (bootstrap-get-slot iwmc-class 'local-supers)
  705. X          (iterate ((i in includes)) (collect (class-named i))))
  706. X    (setf (bootstrap-get-slot iwmc-class 'class-precedence-list)
  707. X          (setq cpl (bootstrap-compute-class-precedence-list iwmc-class)))
  708. X    (setq all-slots (append (iterate ((super in (reverse (cdr cpl))))
  709. X                              (join (bootstrap-get-slot super 'local-slots)))
  710. X                            local-slots))
  711. X    (setf (bootstrap-get-slot iwmc-class 'instance-slots)
  712. X          (setq instance-slots (slots-with-allocation () all-slots :instance)))
  713. X    (setf (bootstrap-get-slot iwmc-class 'non-instance-slots)
  714. X          (slots-with-allocation-not () all-slots :instance))
  715. X    (setf (bootstrap-get-slot iwmc-class 'no-of-instance-slots)
  716. X          (length instance-slots))
  717. X    (setf (bootstrap-get-slot iwmc-class 'local-slots) local-slots)
  718. X    (setf (bootstrap-get-slot iwmc-class 'direct-discriminators) ())
  719. X    (setf (bootstrap-get-slot iwmc-class 'direct-methods) ())
  720. X    (setf (bootstrap-get-slot iwmc-class 'prototype) prototype)
  721. X    (setf (bootstrap-get-slot iwmc-class 'wrapper) wrapper)
  722. X    (setf (bootstrap-get-slot iwmc-class 'ds-options) ds-options)))
  723. X
  724. X(defun bootstrap-compute-class-precedence-list (class)
  725. X  ;; Used by define-meta-braid to compute the class-precedence-list of a class.
  726. X  (let ((local-supers (bootstrap-get-slot class 'local-supers)))
  727. X    (cons class
  728. X          (and local-supers
  729. X               (iterate ((ls in local-supers))
  730. X                 (join (bootstrap-compute-class-precedence-list ls)))))))
  731. X
  732. X;;; bootstrap-meta-braid sets *bootstrap-slots* and builds the meta-braid.
  733. X;;; Note that while it is somewhat general-purpose and driven off of *meta-braid*,
  734. X;;; it has several important built-in assumptions about the meta-braid.
  735. X;;; Namely:
  736. X;;;  - The class of every class in the meta-braid is class.
  737. X;;;  - The class class inherits its slots from every other class in the
  738. X;;;    meta-braid.  Put another way, bootstrap-meta-braid figures out the
  739. X;;;    slots of class by appending the slots of all the other classes
  740. X;;;    in the meta-braid.
  741. X;;;   
  742. X(defmacro bootstrap-meta-braid ()
  743. X  ;; Parse *meta-braid* and setup *bootstrap-slots* so that we can call
  744. X  ;; bootstrap-get-slot to fill in the slotds of the classes we create.
  745. X  (let* ((meta-braid
  746. X           (iterate ((classd in *meta-braid*))
  747. X             (let* ((name (car classd))
  748. X                    (ds-options (parse-defstruct-options ()
  749. X                             name
  750. X                             (cadr classd)))
  751. X                    (slotds (parse-slot-descriptions ()
  752. X                             ds-options
  753. X                             (caddr classd))))
  754. X               (collect (list name ds-options slotds)))))
  755. X         (all-slots-of-class-class
  756. X           (iterate ((classd in meta-braid))
  757. X             (join (caddr classd)))))
  758. X    (setq *bootstrap-slots* (slots-with-allocation ()
  759. X                                                   all-slots-of-class-class
  760. X                                                   :instance))
  761. X    `(progn      
  762. X       (setq *bootstrap-slots* ',*bootstrap-slots*)
  763. X       ;; First make the class class.  It is the class of all the classes in
  764. X       ;; the metabraid so we need it and a wrapper of it so that we can set
  765. X       ;; the wrapped class field of the other metaclasses as we make them.
  766. X       (let* ((class-class
  767. X        (%allocate-class-class ,(length *bootstrap-slots*)))
  768. X              (wrapper-of-class-class (make-class-wrapper class-class)))
  769. X         ,@(iterate ((classd in meta-braid))
  770. X             (collect
  771. X               (destructuring-bind (met-name met-ds-options met-slotds)
  772. X                   classd
  773. X                 (let ((met-includes (ds-options-includes met-ds-options)))
  774. X                   `(let* ((name ',met-name)
  775. X                           (includes ',met-includes)
  776. X                           (ds-options ',met-ds-options)
  777. X                           (slotds ',met-slotds)
  778. X                           (class ,(if (eq met-name 'class)
  779. X                                       'class-class
  780. X                                       `(%allocate-instance--class
  781. X                                          ,(length *bootstrap-slots*)
  782. X                      (class-named 'class))))
  783. X                           (class-wrapper ,(if (eq met-name 'class)
  784. X                                               'wrapper-of-class-class
  785. X                                               '(make-class-wrapper class))))
  786. X                      (setf (iwmc-class-class-wrapper class)
  787. X                wrapper-of-class-class)
  788. X                      (setf (class-named name) class)
  789. X                      (bootstrap-initialize class
  790. X                                            name
  791. X                                            includes
  792. X                                            slotds
  793. X                                            (if (eq class class-class)
  794. X                        class
  795. X                        ())
  796. X                                            class-wrapper
  797. X                                            ds-options))))))
  798. X         (let ((class-cpl (bootstrap-get-slot class-class
  799. X                          'class-precedence-list)))
  800. X           (iterate ((sub in class-cpl)
  801. X                     (sup in (cdr class-cpl)))
  802. X             (push sub (bootstrap-get-slot sup 'direct-subclasses)))))
  803. X       ;; CLASS-INSTANCE-SLOTS has to be defined specially!
  804. X       ;; It cannot be defined in terms of get-slot since it is the method
  805. X       ;; that the get-slot mechanism (actually get-slot-using-class) appeals
  806. X       ;; to to find out what slots are in an instance of a particular class.
  807. X       ;;
  808. X       ;; The fact that class-instance-slots is defined specially this way
  809. X       ;; means that any change to the class class which changes the location
  810. X       ;; of the instance-slots slot must redefine and recompile
  811. X       ;; class-instance-slots.
  812. X       (defun class-instance-slots (class)
  813. X         (get-static-slot--class class
  814. X           ,(%convert-slotd-position-to-slot-index
  815. X              (slotd-position 'instance-slots *bootstrap-slots*))))
  816. X       (defun class-non-instance-slots (class)
  817. X         (get-static-slot--class class
  818. X           ,(%convert-slotd-position-to-slot-index
  819. X              (slotd-position 'non-instance-slots *bootstrap-slots*))))
  820. X       ;; Now define the other accessors and :setf methods for those
  821. X       ;; accessors.
  822. X       ,@(iterate ((classd in meta-braid))
  823. X           (destructuring-bind (name () slotds) classd
  824. X             (join
  825. X               (iterate ((slotd in slotds))
  826. X                 (let* ((slot-name (slotd-name slotd))
  827. X                        (accessor-name (slotd-accessor slotd)))
  828. X                   (unless (memq slot-name '(instance-slots
  829. X                         non-instance-slots))
  830. X                     (collect
  831. X                       `(defmeth ,accessor-name ((,name ,name))
  832. X                          (funcall ,(or (slotd-get-function slotd)
  833. X                    ''get-slot)
  834. X                                   ,name
  835. X                                   ',(slotd-name slotd)))))
  836. X                   (collect
  837. X                     `(defmeth (,accessor-name (:setf (.new_value.)))
  838. X                ((,name ,name))
  839. X                        (funcall ,(or (slotd-put-function slotd) ''put-slot)
  840. X                                 ,name
  841. X                                 ',(slotd-name slotd)
  842. X                                 .new_value.))))))))
  843. X       t)))
  844. X
  845. X
  846. X(eval-when (eval load)
  847. X  (clrhash *class-name-hash-table*)
  848. X  (bootstrap-meta-braid)
  849. X  (recompile-class-of))
  850. X
  851. X(defmeth class-slots ((class class))
  852. X  (append (class-non-instance-slots class)
  853. X      (class-instance-slots class)))
  854. X
  855. X(defmeth (class-direct-methods (:setf (nv))) ((class class))
  856. X  (setf (get-slot class 'direct-methods) nv)
  857. X  (dolist (m nv) (pushnew (method-discriminator m)
  858. X              (get-slot class 'direct-discriminators))))
  859. X
  860. END_OF_FILE
  861. if test 34250 -ne `wc -c <'braid.l'`; then
  862.     echo shar: \"'braid.l'\" unpacked with wrong size!
  863. fi
  864. # end of 'braid.l'
  865. fi
  866. echo shar: End of archive 10 \(of 13\).
  867. cp /dev/null ark10isdone
  868. MISSING=""
  869. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  870.     if test ! -f ark${I}isdone ; then
  871.     MISSING="${MISSING} ${I}"
  872.     fi
  873. done
  874. if test "${MISSING}" = "" ; then
  875.     echo You have unpacked all 13 archives.
  876.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  877. else
  878.     echo You still need to unpack the following archives:
  879.     echo "        " ${MISSING}
  880. fi
  881. ##  End of shell archive.
  882. exit 0
  883. -- 
  884.  
  885. Rich $alz            "Anger is an energy"
  886. Cronus Project, BBN Labs    rsalz@bbn.com
  887. Moderator, comp.sources.unix    sources@uunet.uu.net
  888.